package adoption;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

import Util.Util;
import book.Book;

import term.dept.Department;
import term.dept.course.Course;
import term.dept.course.section.Section;

import exception.InvalidStatusException;

/**
 * Represents a book adoption for a section of a course.
 * Includes references to the Department, Course, Section,
 * Book, Status, and adoptions of this book in other sections.
 * @author SJP
 *
 */
public class Adoption {
	
	/**
	 * Valid status strings
	 */
	private static String req = "Req",
				   		  opt = "Opt",
				   		  alt = "Alt",
				   		  pc = "PC",
				   		  nt = "NO TEXT",
				   		  na = "NO INFO",
				   		  lm = "LAB MAN",
				   		  error = "ERR";

	/**
	 * Represents valid statuses of book adoptions.
	 * @author SJP
	 *
	 */
	public static enum Status {

		REQ (req),
		OPT (opt),
		ALT (alt),
		PC (pc),
		NT (nt),
		NA (na),
		LM (lm),
		ERROR (error);
		
		/**
		 * This status string
		 */
		private String status;
		
		/**
		 * Create new status object with the given string.
		 * ASSUMES THE STRING IS VALID.
		 * @param stat
		 */
		private Status(String stat) {
			status = stat;
		}
		
		public static Status req() {return REQ;}
		
		public static Status opt() {return OPT;}
		
		public static Status alt() {return ALT;}
		
		public static Status pc() {return PC;}
		
		public static Status nt() {return NT;}
		
		public static Status na() {return NA;}
		
		public static Status lm() {return LM;}
		
		public static Status error() {return ERROR;}
		
		/**
		 * @return true if status is required, else false.
		 */
		public boolean isReq() {return is(req);}
		
		/**
		 * @return true if status is optional, else false.
		 */
		public boolean isOpt() {return is(opt);}
		
		/**
		 * @return true if status is alternate, else false.
		 */
		public boolean isAlt() {return is(alt);}
		
		/**
		 * @return true if status is package component, else false.
		 */
		public boolean isPC() {return is(pc);}
		
		/**
		 * @return true if status is no text, else false.
		 */
		public boolean isNT() {return is(nt);}
		
		/**
		 * @return true if status is no info, else false.
		 */
		public boolean isNA() {return is(na);}
		
		/**
		 * @return true if status is error, else false.
		 */
		public boolean isError() {return is(error);}
		
		/**
		 * @return true if status matches the given string, else false.
		 */
		private boolean is(String s) {return status.equals(s);}

		/**
		 * @return the status as a string.
		 */
		public String toString() {return status;}
		
		/**
		 * @return true if s is a valid status string.
		 */
		public static boolean isValid(String s) {
			if (s.equals(ERROR))
				return false;
			boolean out = false;
			out |= s.equals(req);
			out |= s.equals(opt);
			out |= s.equals(alt);
			out |= s.equals(pc);
			
			return out;
		}
		
		/**
		 * Returns the proper Status object for a given status string.
		 * @param s status string
		 * @return a static Status object for the given string
		 * @throws InvalidStatusException if an invalid status string is given
		 */
		public static Status getStatus(String s){
						
			// check each valid type of status
			if (s.startsWith(req))
				return req();
			else if (s.startsWith(opt))
				return opt();
			else if (s.startsWith(alt))
				return alt();
			else if (s.startsWith(pc))
				return pc();
			else if (s.startsWith(na))
				return na();
			else if (s.startsWith(nt))
				return nt();
			else if (s.startsWith(lm))
				return lm();
			
			//shouldn't reach here, error case.
			Util.printErrorString("Status string: "+s+" is in error");
			return error();
				
		}
	}

	//private static Connection con;
	//private static PreparedStatement pstmt;

	private Section sec;
	private Book bk;
	private int id;
	private static int nextID = 0;
	
	/**
	 * Status of the book. Req/Opt/Alt/PC/ERROR
	 */
	private Status stat;
	
	/**
	 * Other adoptions of this book.
	 */
	private AdoptionMap related;

	/**
	 * Create a new adoption from Dept, Course, Sec, Book, and status.
	 * @param d dept
	 * @param c course
	 * @param s section
	 * @param b book
	 * @param status
	 * @throws InvalidStatusException
	 */
	public Adoption(Section s, Book b, String status) {
		this(s,b,status,nextID++);
	}
	
	public Adoption(Section s, Book b, String status, int nid) {
		sec = s;
		bk = b;
		id = nid;
		stat = Status.getStatus(status);	// throws InvalidStatusException

		//sec.addAdoption(this);
	}
	
	/**
	 * @return the department of this adoption
	 */
	public Department getDept() {return sec.getDept();}
	
	/**
	 * @return the course of this adoption
	 */
	public Course getCourse() {return sec.getCourse();}
	
	/**
	 * @return the section of this adoption
	 */
	public Section getSection() {return sec;}
	
	/**
	 * @return the book of this adoption
	 */
	public Book getBook() {return bk;}
	
	/**
	 * @return the status of this adoption
	 */
	public String getStatus() {return stat.toString();}
	
	/**
	 * @return the full course ID of this adoption
	 */
	public String getCourseID() {return getDept().getCode()+""+getCourse().getNumber()+" "+sec.getID();}
	
	/**
	 * @return the id number of this adoption
	 */
	public int getID() {return id;}
	
	/**
	 * @return all related adoptions
	 */
	public AdoptionMap getRelated() {return related;}
	
	/**
	 * Add related adoption.
	 * @param a related adoption to add.
	 * @return
	 */
	public Adoption addRelated(Adoption a) {
		//todo
		return a;
	}
	
	/**
	 * @return true if the given book is used in this adoption, else false.
	 */
	public boolean contains(Book b) {return bk == b;}
	
	public String toString() {return getCourseID()+": "+getBook().toString()+" "+getStatus();}
	
	/*public void save() throws SQLException {
		pstmt.setInt(1, id);
		pstmt.setString(2, getDept().getCode().toString());
		pstmt.setInt(3, getCourse().getNumber());
		pstmt.setString(4, getSection().getID());
		pstmt.setString(5, String.valueOf(getBook().getISBN()));
		pstmt.setString(6, getStatus());
		
		pstmt.execute();
	}
	
	public static void saveCount() throws SQLException {
		pstmt.setInt(1,nextID);
		pstmt.setString(2, "APTC");
		pstmt.setInt(3, 0);
		pstmt.setString(4, " ");
		pstmt.setString(5, " ");
		pstmt.setString(6, " ");
		
		pstmt.execute();
	}*/

	/**
	 * @param nextID the nextID to set
	 */
	public static void setNextID(int nextID) {
		Adoption.nextID = nextID;
	}
}
